package com.penghaonan.appframework.utils

import android.content.ContentResolver
import android.content.ContentValues
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.text.TextUtils
import android.webkit.MimeTypeMap
import androidx.core.content.FileProvider
import com.penghaonan.appframework.AppDelegate
import com.penghaonan.appframework.utils.Logger.Companion.e
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.FileWriter
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import java.math.BigInteger
import java.net.HttpURLConnection
import java.net.MalformedURLException
import java.net.URL
import java.security.MessageDigest

object FileUtils {
    private const val TAG = "FileUtils"

    /**
     * 获取文件后缀
     */
    fun getSuffix(file: File?): String? {
        if (file == null || !file.exists() || file.isDirectory) {
            return ""
        }
        val fileName = file.name
        return getSuffix(fileName)
    }

    /**
     * 获取文件后缀
     */
    fun getSuffix(fileName: String): String? {
        if (fileName == "" || fileName.endsWith(".")) {
            return null
        }
        val index = fileName.lastIndexOf(".")
        return if (index != -1) {
            fileName.substring(index + 1).lowercase()
        } else {
            ""
        }
    }

    fun buildFileName(path: String, fileName: String, suffix: String, index: Int): File {
        var path = path
        var fileName = fileName
        var suffix = suffix
        var index = index
        var file: File
        if (!path.endsWith("/")) {
            path += "/"
        }
        if (!suffix.startsWith(".")) {
            suffix = ".$suffix"
        }
        fileName = fileName.replace(suffix, "")
        //下标不等于0开始拼后缀
        file = if (index != 0) {
            File("$path$fileName($index)$suffix")
        } else {
            File(path + fileName + suffix)
        }
        //判断文件是否存在 文件不存在退出递归
        if (file.isFile) {
            //每次递归给下标加1
            file = buildFileName(path, fileName, suffix, ++index)
        }
        return file
    }

    /**
     * 获取文件MimeType
     */
    fun getMimeType(file: File?): String {
        val def = "file/*"
        val suffix = getSuffix(file)
        return getMimeTypeBySuffix(suffix)
    }

    fun getMimeType(fileName: String): String {
        val suffix = getSuffix(fileName)
        return getMimeTypeBySuffix(suffix)
    }

    fun getMimeTypeBySuffix(suffix: String?): String {
        val def = "file/*"
        if (suffix == null) {
            return def
        }
        val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(suffix)
        if (type != null && !type.isEmpty()) {
            return type
        }
        return def
    }

    fun compareFile(file1: File?, file2: File?): Boolean {
        if (file1 == null || file2 == null || !file1.exists() || !file2.exists()) {
            return false
        }
        return file1.length() == file2.length() && TextUtils.equals(
            getFileMD5(file1),
            getFileMD5(file2)
        )
    }

    fun copyFileToFile(fileFrom: File, fileTo: File?, listener: CopyFileListener?): Boolean {
        try {
            if (fileTo != null && !fileTo.exists()) { //文件不存在时
                val inStream: InputStream = FileInputStream(fileFrom.absolutePath)
                return saveStreamToFile(fileFrom.length(), inStream, fileTo, listener)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }

    private fun saveStreamToFile(
        size: Long,
        inStream: InputStream,
        fileTo: File,
        listener: CopyFileListener?
    ): Boolean {
        var size = size
        if (size <= 0) {
            size = Long.MAX_VALUE
        }
        try {
            listener?.onProgress(0f)
            var bytesum = 0
            var byteread = 0
            val fs = FileOutputStream(fileTo.absolutePath)
            val buffer = ByteArray(1024)
            while ((inStream.read(buffer).also { byteread = it }) != -1) {
                bytesum += byteread //字节数 文件大小
                fs.write(buffer, 0, byteread)
                if (listener != null) {
                    val abort = listener.onProgress((bytesum.toFloat()) / size)
                    if (abort) {
                        break
                    }
                }
            }
            inStream.close()
            listener?.onProgress(1f)
            return true
        } catch (e: Exception) {
            e(e)
        }
        listener?.onProgress(1f)
        return false
    }

    fun copyUriToFile(srcUri: Uri, fileTo: File, listener: CopyFileListener?): Boolean {
        try {
            val inputStream =
                AppDelegate.getApp().contentResolver.openInputStream(srcUri) ?: return false
            saveStreamToFile(getUriFileSize(srcUri), inputStream, fileTo, listener) //调用下面的方法存储
            inputStream.close()
            return true //成功返回路径
        } catch (e: Exception) {
            e.printStackTrace()
            return false
        }
    }

    private fun getUriFileSize(uri: Uri): Long {
        if (ContentResolver.SCHEME_FILE == uri.scheme) {
            return File(uri.path).length()
        } else if (ContentResolver.SCHEME_CONTENT == uri.scheme) {
            try {
                val descriptor = AppDelegate.getApp().contentResolver.openFileDescriptor(uri, "r")
                if (descriptor != null) {
                    return descriptor.statSize
                }
            } catch (e: FileNotFoundException) {
                e(e)
            }
        }
        return 0
    }

    fun openFolder(dir: File?) {
        if (null == dir || !dir.exists()) {
            return
        }

        val intent = Intent(Intent.ACTION_VIEW, Uri.fromFile(dir))
        AppDelegate.startActivity(intent)
    }

    fun getFileMD5(file: File?): String? {
        return getFileMD5(file, 16)
    }

    fun getFileMD5(file: File?, radix: Int): String? {
        if (file == null || !file.isFile || !file.exists()) {
            return null
        }
        var digest: MessageDigest? = null
        var `in`: FileInputStream? = null
        val buffer = ByteArray(1024)
        var len: Int
        try {
            digest = MessageDigest.getInstance("MD5")
            `in` = FileInputStream(file)
            while ((`in`.read(buffer, 0, 1024).also { len = it }) != -1) {
                digest.update(buffer, 0, len)
            }
            `in`.close()
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
        val bigInt = BigInteger(1, digest.digest())
        return bigInt.toString(radix)
    }

    val authority: String
        get() = AppDelegate.getApp().packageName + ".fileprovider"

    fun uriFromFile(file: File?): Uri {
        return FileProvider.getUriForFile(AppDelegate.getApp(), authority, file!!)
    }

    fun saveBitmapToFile(bitmap: Bitmap?, file: File?): Boolean {
        if (file == null) {
            return false
        }

        var fileOutputStream: FileOutputStream? = null
        try {
            fileOutputStream = FileOutputStream(file)
            if (bitmap != null) {
                if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) {
                    fileOutputStream.flush()
                    return true
                }
            }
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            try {
                fileOutputStream?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        return false
    }

    fun saveTextToFile(text: String?, file: File?): Boolean {
        if (file == null) {
            return false
        }
        if (!file.exists()) {
            try {
                if (!file.createNewFile()) {
                    return false
                }
            } catch (e: IOException) {
                e(e)
                return false
            }
        }
        try {
            val writer = FileWriter(file, true)
            val bufferedWriter = BufferedWriter(writer)
            bufferedWriter.write(text)
            bufferedWriter.flush()
            writer.flush()
            bufferedWriter.close()
            writer.close()
            return true
        } catch (e: IOException) {
            e(e)
        }
        return false
    }

    @JvmStatic
    fun readStringFromAssets(fileName: String?): String {
        var str = ""
        try {
            val inputStreamReader = InputStreamReader(
                AppDelegate.getApp().assets.open(
                    fileName!!
                ), "UTF-8"
            )
            val bufferedReader = BufferedReader(inputStreamReader)
            var line: String?
            val stringBuilder = StringBuilder()
            while ((bufferedReader.readLine().also { line = it }) != null) {
                stringBuilder.append(line).append("\n")
            }
            bufferedReader.close()
            inputStreamReader.close()
            str = stringBuilder.toString()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return str
    }

    fun readStringFromFile(file: File): String? {
        if (file.exists()) {
            var result: StringBuilder? = null
            try {
                val fis = FileInputStream(file)
                val reader = InputStreamReader(fis)
                val bufferedReader = BufferedReader(reader)
                var line: String?
                result = StringBuilder()
                while ((bufferedReader.readLine().also { line = it }) != null) {
                    result.append(line)
                }
            } catch (e: Exception) {
                e(e)
            }
            return result?.toString()
        } else {
            return null
        }
    }

    fun readStringFromUri(uri: Uri): String? {
        val assetHeader = "file:///android_asset/"
        if (uri.toString().startsWith(assetHeader)) {
            return readStringFromAssets(uri.toString().replace(assetHeader, ""))
        }
        try {
            val contentResolver = AppDelegate.getApp().contentResolver
            val inputStream = contentResolver.openInputStream(uri)
            val reader = BufferedReader(InputStreamReader(inputStream))
            val sb = StringBuilder()
            while (reader.ready()) {
                sb.append(reader.readLine())
            }
            return sb.toString()
        } catch (e: FileNotFoundException) {
            e(e)
        } catch (e: IOException) {
            e(e)
        }
        return null
    }

    fun getNetFileSize(url: String?): Long {
        try {
            val url1 = URL(url)
            val uc = url1.openConnection() as HttpURLConnection
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                return uc.contentLengthLong
            } else {
                uc.requestMethod = "HEAD"
                uc.setRequestProperty(
                    "User-Agent",
                    "Mozilla/5.0 (Windows 7; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36 YNoteCef/5.8.0.1 (Windows)"
                )
                return uc.contentLength.toLong()
            }
        } catch (e: MalformedURLException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return -1
    }

    fun saveImage2MediaStore(file: File) {
        val localContentResolver = AppDelegate.getApp().contentResolver
        val localContentValues = getImageContentValues(file, System.currentTimeMillis())
        localContentResolver.insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            localContentValues
        )

        val localIntent = Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE")
        val localUri = Uri.fromFile(file)
        localIntent.setData(localUri)
        AppDelegate.getApp().sendBroadcast(localIntent)
    }

    private fun getImageContentValues(paramFile: File, paramLong: Long): ContentValues {
        val localContentValues = ContentValues()
        localContentValues.put("title", paramFile.name)
        localContentValues.put("_display_name", paramFile.name)
        localContentValues.put("mime_type", "image/jpeg")
        localContentValues.put("datetaken", paramLong)
        localContentValues.put("date_modified", paramLong)
        localContentValues.put("date_added", paramLong)
        localContentValues.put("orientation", 0)
        localContentValues.put("_data", paramFile.absolutePath)
        localContentValues.put("_size", paramFile.length())
        return localContentValues
    }

    /**
     * 保存视频
     *
     * @param file
     */
    fun saveVideo2MediaStore(file: File) {
        //是否添加到相册
        val localContentResolver = AppDelegate.getApp().contentResolver
        val localContentValues = getVideoContentValues(file, System.currentTimeMillis())
        val localUri = localContentResolver.insert(
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
            localContentValues
        )
        AppDelegate.getApp().sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri))
    }

    private fun getVideoContentValues(paramFile: File, paramLong: Long): ContentValues {
        val localContentValues = ContentValues()
        localContentValues.put("title", paramFile.name)
        localContentValues.put("_display_name", paramFile.name)
        localContentValues.put("mime_type", "video/mp4")
        localContentValues.put("datetaken", paramLong)
        localContentValues.put("date_modified", paramLong)
        localContentValues.put("date_added", paramLong)
        localContentValues.put("_data", paramFile.absolutePath)
        localContentValues.put("_size", paramFile.length())
        return localContentValues
    }

    fun getFileName(uri: Uri, defaultName: String): String {
        val path = uri.path
        if (TextUtils.isEmpty(path)) {
            return defaultName
        }
        val beginIndex = path!!.lastIndexOf("/")
        val lastIndex = path.lastIndexOf(".")
        if (beginIndex < 0) {
            return defaultName
        }
        if (beginIndex < lastIndex) {
            return path.substring(beginIndex + 1, lastIndex)
        }
        return path.substring(beginIndex)
    }

    interface CopyFileListener {
        /**
         * @return true abort
         */
        fun onProgress(progress: Float): Boolean
    }
}